/*
 * MIT License
 *
 * Copyright (c) 2024 YiChengJin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
 
#include "el_kobj.h"
#include "el_kheap.h"
#include "el_kpool.h"

#define KOBJ_PPOOL_BASE_INIT() 0

/* initialise kernel object */
#define KOBJ_BASE_INFO_INIT( kobj_type, kobj_struct, kobj_ppool, pool_size)\
		{\
		  .Kobj_type = (EL_KOBJTYPE_T)kobj_type, .Kobj_size = sizeof(kobj_struct),\
		  .Kobj_Basepool = (void *)kobj_ppool  , .Kobj_PoolSize = pool_size }

/*  kernel object basic context */
static kobj_context_t kobj_context_table[EL_KOBJ_TYPE_MAX] = {
#if THREAD_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_PTCB,		 	thread_t,		KOBJ_PPOOL_BASE_INIT() , THREAD_POOLSIZE 	    ),
#endif
	
#if EL_USE_THREAD_PENDING && THREAD_PENDING_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_TICKPENDING,	TickPending_t,	KOBJ_PPOOL_BASE_INIT() , THREAD_PENDING_POOLSIZE),
#endif
	
#if EL_USE_THREAD_SUSPEND && THREAD_SUSPEND_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_SUSPEND,	 	Suspend_t,		KOBJ_PPOOL_BASE_INIT() , THREAD_SUSPEND_POOLSIZE),
#endif
	
#if EL_USE_MUTEXLOCK   	  && MUTEXLOCK_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_MUTEXLOCK,		mutex_lock_t,	KOBJ_PPOOL_BASE_INIT() , MUTEXLOCK_POOLSIZE 	),
#endif
	
#if EL_USE_MESSAGE_QUEUE  && MESSAGE_QUEUE_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_MESSAGE_QUEUE, msg_q_t, 		KOBJ_PPOOL_BASE_INIT() , MESSAGE_QUEUE_POOLSIZE ),
#endif
	
#if EL_USE_KTIMER 		  && KTIMER_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_kTIMER,	 	kTimer_t,		KOBJ_PPOOL_BASE_INIT() , KTIMER_POOLSIZE 		),
#endif

#if EL_USE_SEM 		  	  && SEM_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_SEM,	 	 	sem_t,			KOBJ_PPOOL_BASE_INIT() , SEM_POOLSIZE 		    ),
#endif

#if EL_USE_EVENTFLAG 	  && EVENTFLAG_OBJ_STATIC
	KOBJ_BASE_INFO_INIT( EL_KOBJ_EVTFLG,	 	evtflg_t,		KOBJ_PPOOL_BASE_INIT() , EVENTFLAG_POOLSIZE 	),
#endif
};

/* take context of kernel object */
__API__ EL_RESULT_T kobj_check( EL_KOBJTYPE_T obj_type, kobj_context_t * pobj )
{
	kobj_context_t * kobj_info;
	
	if((pobj == (kobj_context_t *)0)||((EL_KOBJTYPE_T)obj_type >= EL_KOBJ_TYPE_MAX))
			return EL_RESULT_ERR;
	
	kobj_info = &(kobj_context_table[(EL_KOBJTYPE_T)obj_type]);
	
	/* match table */
	if( kobj_info->Kobj_type == obj_type){
		pobj->Kobj_Basepool = kobj_info->Kobj_Basepool;
		pobj->Kobj_size = kobj_info->Kobj_size;
		pobj->Kobj_type = kobj_info->Kobj_type;
	}
	else{
		return EL_RESULT_ERR;
	}
	
	return EL_RESULT_OK;
}

/* allocate pool for kernel object */
void * kobj_pool_request(EL_KOBJTYPE_T kobj_type,EL_UINT ticks)
{
	kobj_context_t * kobj_info;
	
	if( kobj_type >= EL_KOBJ_TYPE_MAX )
	 return (void *)0;
	
	kobj_info = &(kobj_context_table[(EL_KOBJTYPE_T)kobj_type]);
	if( kobj_info->Kobj_Basepool != NULL ){
		return (void *)kobj_info->Kobj_Basepool;
	}
	
	kobj_info->Kobj_Basepool = (hp_alloc_no_sys( sysheap_hcb, kobj_info->Kobj_PoolSize ));
	
	/* initialise kernel object pool */
	EL_stKpoolInitialise(kobj_info->Kobj_Basepool,kobj_info->Kobj_PoolSize,kobj_info->Kobj_size);
	
	return kobj_info->Kobj_Basepool;
}

/* allocate one blk form kernel object pool */
__API__ void * kobj_alloc(EL_KOBJTYPE_T kobj_type)
{
	void * pool;
	
	if((EL_KOBJTYPE_T)kobj_type >= EL_KOBJ_TYPE_MAX)
		return NULL;
	
	pool = kobj_context_table[kobj_type].Kobj_Basepool;
	
	if(pool == NULL) return NULL;
	
	return EL_stKpoolBlockTryAlloc(pool);
}

/* free one blk form kernel object pool */
__API__ void kobj_free(EL_KOBJTYPE_T kobj_type,void * pobj_blk)
{
	void * pool;
	
	if(((EL_KOBJTYPE_T)kobj_type >= EL_KOBJ_TYPE_MAX) || (pobj_blk == NULL))
		return;
	
	pool = kobj_context_table[kobj_type].Kobj_Basepool;
	
	if(pool == NULL) return;
	
	EL_stKpoolBlockFree(pool,pobj_blk);
	
}